#include "tool.h"
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/bio.h>
#include <openssl/objects.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <unistd.h>
#include "assert.h"
#include "string.h"
#include <chrono>
#include "public_define.h"
#include <sys/time.h>
static const char fillchar = '=';

const std::string Base64Table(
    // 0000000000111111111122222222223333333333444444444455555555556666
    // 0123456789012345678901234567890123456789012345678901234567890123
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
std::string getFileMd5(std::string filePath)
{
    // auto filepath = getFileName();
    // std::cout << "-----------------filepath:" << filePath << std::endl;
    uint8_t vMD5_result[16] = {0};
    char vMD5Str[32 + 1] = {0};
    SignUtils_GetFileMD5(filePath.c_str(), (uint8_t *)vMD5_result);
    StrUtils_BytesToHexStr(vMD5_result,
                           sizeof(vMD5_result),
                           vMD5Str,
                           sizeof(vMD5Str)); //不需要依赖
    std::string ret(vMD5Str);
    // std::cout << "filemd5:" << ret << std::endl;
    return ret;
}

int32_t SignUtils_GetFileMD5(const char *pvFilePath, uint8_t *pvMD5Out)
{
    FILE *pvFd = NULL;
    MD5_CTX mdContext;
    uint8_t *pvData = NULL;
    uint32_t vLen = 0;

    assert(pvMD5Out != NULL);

    if (pvFilePath != NULL && strlen(pvFilePath) > 0)
    {
        pvFd = fopen(pvFilePath, "r");
    }

    if (pvFd == NULL)
    {
        // LOGE("Open system cert file fail");
        return -1;
    }

    pvData = (uint8_t *)calloc(1, 100 * 1024);
    if (pvData == NULL)
    {
        fclose(pvFd);
        return -1;
    }
    // REQUIRE(pvData, REQUIRE_MSG_ALLOCATION);

    MD5_Init(&mdContext);

    while (0 != (vLen = fread(pvData, 1, 100 * 1024, pvFd)))
    {
        MD5_Update(&mdContext, pvData, vLen);
    }

    MD5_Final((unsigned char *)pvMD5Out, &mdContext);

    fclose(pvFd);
    free(pvData);
    pvData = NULL;

    return 0;
}

int StrUtils_BytesToHexStr(uint8_t input_Bytes[], uint32_t BytesLen, char *output_HexStr, uint32_t out_len)
{
    uint32_t i;
    assert(input_Bytes != NULL);
    assert(output_HexStr != NULL);

    char *pTempBuf = NULL;

    if (BytesLen > 0)
    {
        pTempBuf = (char *)calloc(1, BytesLen * 2 + 1);
        if (pTempBuf == NULL)
        {
            return 0;
        }
        // REQUIRE(pTempBuf, REQUIRE_MSG_ALLOCATION);

        for (i = 0; i < BytesLen; i++)
        {
            sprintf(&pTempBuf[i * 2], "%02X", input_Bytes[i]);
        }

        pTempBuf[BytesLen * 2] = '\0'; // Need improve StrUtils_BytesToHexStr

        strncpy(output_HexStr, pTempBuf, out_len);

        free(pTempBuf);
        pTempBuf = NULL;

        return strlen(output_HexStr);
    }
    else
    {
        return 0;
    }
}

uint64_t getTime()
{
    uint64_t time = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
    return time;
}
double getDoubleTime()
{
    struct timeval curTime;
    gettimeofday(&curTime,nullptr);
    double dtime_ = curTime.tv_sec + curTime.tv_usec / static_cast<double>(1e6);
    return dtime_;
}
void getReqID(std::string &reqId)
{
    //得到序号
    static int seqNum = 0;
    //取得时间毫秒数
    // struct timeval curTime;
    // gettimeofday(&curTime);
    // double mills = curTime.tv_sec + curTime.tv_usec/1000;

    u_int64_t timems =
        std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();

    reqId = std::to_string(timems);
    // std::cout << "reqId:" << reqId << std::endl;

    if (seqNum < 10)
    {
        reqId = reqId + "00" + std::to_string(seqNum);
    }
    else if (seqNum < 100)
    {
        reqId = reqId + "0" + std::to_string(seqNum);
    }
    else
    {
        reqId = reqId + std::to_string(seqNum);
    }

    // sprintf(reqId.c_str(),"%f%03d",timems,seqNum);
    if (seqNum >= 998)
    {
        seqNum = 0;
    }
    else
    {
        seqNum += 2;
    }
}

std::string RandStr(const int len)
{
    srand((int)time(0)); // 产生随机种子  把0换成NULL也行
    std::string temp;
    for (int i = 0; i < len; i++)
    {
        switch (rand() % 3)
        {
        case 0:
            temp += rand() % 10 + '0';
            break;

        case 1:
            temp += rand() % 26 + 'a';
            break;

        case 2:
            temp += rand() % 26 + 'A';
            break;
        }
    }
    return temp;
}

std::string encodeFromArray(const uint8_t *data, size_t len)
{
    size_t i;
    char c;
    std::string ret;

    ret.reserve(len * 2);

    for (i = 0; i < len; ++i)
    {
        c = (data[i] >> 2) & 0x3f;
        ret.append(1, Base64Table[c]);
        c = (data[i] << 4) & 0x3f;
        if (++i < len)
        {
            c |= (data[i] >> 4) & 0x0f;
        }

        ret.append(1, Base64Table[c]);
        if (i < len)
        {
            c = (data[i] << 2) & 0x3f;
            if (++i < len)
            {
                c |= (data[i] >> 6) & 0x03;
            }
            ret.append(1, Base64Table[c]);
        }
        else
        {
            ++i;
            ret.append(1, fillchar);
        }

        if (i < len)
        {
            c = data[i] & 0x3f;
            ret.append(1, Base64Table[c]);
        }
        else
        {
            ret.append(1, fillchar);
        }
    }

    return (ret);
}

uint8_t BCC(const uint8_t *data, size_t dataLength)
{
    uint8_t check = 0;
    int i = 0;
    while (dataLength--)
    {
        try
        {
            check ^= data[i++];
        }
        catch (const std::exception &e)
        {
            std::cerr << e.what() << '\n';
        }
    }
    return check;
}
